package cn.com.ethos.search;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.log4j.PropertyConfigurator;

import cn.com.ethos.search.query.Config;
import cn.com.ethos.search.query.QueryServer;


public class SearchMain {

	public static final int OPT_HELP    = 'h';
	public static final int OPT_CONFIG  = 'c';
	public static final int OPT_LOG4J   = 'l';
	public static final int OPT_DIR     = 'd';

	private static final String KEY_PATH = "path";
	private static final String KEY_PORT = "port";
	private static final String KEY_TIME_OUT = "socket.timeout";
	private static final String KEY_THREADS_MIN  = "threads.min";
	private static final String KEY_THREADS_MAX  = "threads.max";
	private static final String KEY_CONTINUE_ON_ERROR = "continue";
	
	
	private static Options OPTIONS = new Options();
	
	static  {
		OPTIONS.addOption(String.valueOf((char)OPT_CONFIG),true,"configuration file,default file is "+ Constants.CONFIG_SERVER_PATH);
		OPTIONS.addOption(String.valueOf((char)OPT_LOG4J),true,"log4j configuration file path. default file is " + Constants.LOG_SERVER_CONFIG);
		OPTIONS.addOption(String.valueOf((char)OPT_DIR),true,"the index directory path,if specified,it will override the value from configuration");
		OPTIONS.addOption(String.valueOf((char)OPT_HELP),false,"print help information");
	}
	
	static final QueryServer server  = new QueryServer();
	static final Config setting = new Config();
	
	public static void main(String[] args) throws Exception{
		
		CommandLineParser parser = new GnuParser();
		CommandLine 	  cmd 	 = parser.parse(OPTIONS, args);
		
		Option[] options = cmd.getOptions();
		String   config  = Constants.CONFIG_SERVER_PATH, 
				 log     = Constants.LOG_SERVER_CONFIG,
				 path    = Constants.Empty;
		
		for(Option o : options ) {
			switch(o.getId()) {
				case OPT_HELP:
					if(cmd.hasOption((char)OPT_HELP)) help();
					continue;
				case OPT_LOG4J:
					log    = cmd.getOptionValue((char)OPT_LOG4J,Constants.LOG_SERVER_CONFIG);
					continue;
				case OPT_DIR:
					path   = cmd.getOptionValue((char)OPT_DIR,Constants.Empty);
					continue;
				case OPT_CONFIG:
					config = cmd.getOptionValue((char)OPT_CONFIG,Constants.CONFIG_SERVER_PATH);
					continue;
			}
			
		}
		
		setupSetting4log(log);
		Properties prop = loadSetting4config(config);
		
		if(path.isEmpty()) {
			if(prop.containsKey(KEY_PATH)) {
				setting.setPath(prop.getProperty(KEY_PATH));
			} else {
				puts("need index directory path,not found from argument or configuration file");
				System.exit(1);
				return;
			}
		} else {
			setting.setPath(path);
		}		
		if(prop.containsKey(KEY_PORT)) {
			try {
				int port = Integer.valueOf(prop.getProperty(KEY_PORT));
				setting.setPort(port);
			} catch(Exception ex) {
				/* forget it ,default value will be used */
			}
		}
		if(prop.containsKey(KEY_THREADS_MAX)) {
			try {
				int max = Integer.valueOf(prop.getProperty(KEY_THREADS_MAX));
				setting.setMaxThreadsNum(max);
			} catch(Exception ex) {}
		}		
		if(prop.containsKey(KEY_THREADS_MIN)) {
			try {
				int min = Integer.valueOf(prop.getProperty(KEY_THREADS_MIN));
				setting.setMinThreadsNum(min);
			} catch(Exception ex) {}
		}
		if(prop.containsKey(KEY_CONTINUE_ON_ERROR)) {
			try {
				boolean b = Boolean.parseBoolean(prop.getProperty(KEY_CONTINUE_ON_ERROR));
				setting.setContinueOnError(b);
			} catch(Exception ex) {}
		}		
		if(prop.containsKey(KEY_TIME_OUT)) {
			try {
				int timeout = Integer.valueOf(prop.getProperty(KEY_TIME_OUT));
				setting.setTimeout(timeout);
			} catch(Exception ex) {}
		}
		
		puts("Server setting is :" + setting.toString());
		puts("Startup service ... ");
		
		Thread t = new Thread(new Runnable(){
			public void run() {
				server.setUp(setting);
				server.service();
			}	
		});
		
		t.setDaemon(true);
		t.start();
		
		try{
			puts("Press enter to stop");
			System.in.read();
			server.shutDown();
			puts("Waiting for server socket closing ...");
			t.join(setting.getTimeout());
			puts("Server was closed successfully");
			
		}catch(Exception ignore) {
			/**ignore exception**/
		}
	}
	
	private	
	static void puts(String s) {
		System.out.println(s);
	}	
	static void help() {
		printHelp();
		puts("Report bugs to <gaoxinzhao@ethos.com.cn>");
		System.exit(0);
	}
	static void printHelp() {
		puts(Constants.Empty);
		HelpFormatter formatter = new HelpFormatter();	
		formatter.setDescPadding(5);
		formatter.printHelp("java cn.com.ethos.search.SearchMain \r\n If you want to get more information while drucene is indexing,please set log4j configuration file for your level \r\n",
				OPTIONS);
	}
	
	static void setupSetting4log(String log) {
		if (!new File(log).isFile()) {
			puts("Can not find the config file for log4j from " + log);
			printHelp();
			System.exit(1);
		} else {
			puts("Loading configuration file for log4j from " + log);
			PropertyConfigurator.configure(log);
		}
	}	
	static Properties loadSetting4config(String config) 
			throws IOException,FileNotFoundException{
		
		Properties prop = new Properties();
		File file       = new File(config);
		
		if(!file.isFile()) {
			puts("Can not find the configuration file for indexer from " + config);
			printHelp();
			System.exit(1);
		} else {
			puts("Loading configuration file for indexer from " + config);
			prop.load(new FileInputStream(file));
		}
		return prop;
	}
	

}
